<!-- 机器人聊天 -->
<template>
  <div class="chat">
    <!-- 背景图 -->
    <div class="bg" :style="{ backgroundImage: `url(${bgImage})`, height: `${innerHeight}px` }"></div>
    <div class="stichyTop" :style="{ top: `${stichyTop}px` }">
      <!-- 头部 -->
      <HeaderPage :aiUserInfo="aiUser" :scheduleTotal />
      <!-- 下载app -->
      <downloadApp :aiUserId />
    </div>
    <div class="content">
      <!-- 占位 -->
      <!-- <div class="placeholder" v-if="messages.length < 2" :style="{ height: `${stichyTop}px` }"></div> -->
      <!-- 机器人信息 -->
      <div class="botInfo">
        <BotInfo :aiUserInfo="aiUser" v-if="aiUser" />
      </div>
      <!-- 消息列表 -->
      <Messages :messages :aiUserId :status="messageStatus" @recommendReplyChange="handleRecommendReplyChange" />
    </div>
    <!-- 底部操作拦 -->
    <BottomBar
      @inputAndroidFocus="handleInputAndroidFocus"
      @inputFocus="handleFocus"
      @send-msg="handleSendMsg"
      @sendMsgLoding="handleSendMsgLoding"
      :recommendReply
      :buttonStatus="buttonStatus"
      :aiUserId
      @inputBlur="handleInputBlur"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, onBeforeMount, onMounted, watch, onUnmounted, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import Messages from './components/messages/index.vue'
import BottomBar from './components/bottom-bar/index.vue'

import BotInfo from './components/bot-info/index.vue'
import downloadApp from './components/down-app-fix/index.vue'
import HeaderPage from './components/header/index.vue'
import { IMessage, AiUserInfo } from './types'
import { MessageType } from '@/view/simulator/types'
import { getAiChatListMsgHistory, creatAiChat, getChatStatus } from '@/api/chat'
import dayjs from 'dayjs'
import { handleImagShow } from './helpers'
// 轮询时间
const TIME_GET_MSG_HISTORY = 3000

const route = useRoute()
// 页面进入的bot_id
const {
  params: { bot_id },
} = route
// title的stichyTop
const stichyTop = ref<number>(0)
// sendLoaind
const sendLoading = ref<boolean>(false)
// ios的可视高度
const visualViewportHeight = ref<number>(window?.visualViewport?.height || 0)
// 页面的实际高度
const innerHeight = ref<number>(0)
// 定义一个当前发送的状态
const messageStatus = ref<string>('inProgress')
// 消息列表
const messages = ref<IMessage[]>([])
// ai的信息
const aiUser = ref<AiUserInfo>()
// ai的默认好感度
const defaultIntimacy = ref<number>(0)
// 当前的亲密度总分
const scheduleTotal = ref<number>(0)
// 自己发送的消息条数
const messageConunt = ref<number>(0)
// 轮训拉历史消息的timer
const timer = ref<NodeJS.Timeout>()
// 机器人id
const aiUserId = ref<number>(+bot_id)
// 记录一下消息发送的次数
const messageSendCount = ref<number>(0)
// 限制的可聊天条数
const freeChatTime = ref<number>(5)
// 按钮状态
const buttonStatus = ref<boolean>(true)
// 推荐回复
const recommendReply = ref<string[]>([])
// 拉历史消息的page入参
const pageParams = ref({
  limit: 20,
  max_msg_id: 0,
  order: 1,
  min_msg_id: 0,
})
// 页面的背景图
const bgImage = ref<string>('')

// 滚动到底部
const scrollIntoBottom = (MsgID: number) => {
  const doc = document.getElementById(`message_item_${MsgID}`)
  if (doc) {
    doc.scrollIntoView(true)
  }
}

// 处理安卓获取焦点的事件
const handleInputAndroidFocus = () => {
  // 获取焦点的时候，将滚动条滚动到底部
  if (messages.value.length < 3) return
  scrollIntoBottom(messages.value.slice(-1)[0].MsgID)
}
// ios 需要重新计算一下头部的定位位置
const handleVisualViewportChange = () => {
  const changSize = visualViewportHeight.value - (window?.visualViewport?.height || 0)
  // 处理顶层的top变化
  stichyTop.value = changSize
  handleInputAndroidFocus()
}

// 处理一下ios的键盘弹起
const handleFocus = () => {
  if (!window.visualViewport) return
  window.visualViewport.addEventListener('resize', handleVisualViewportChange)
}
// 处理一下键盘的收起
const handleInputBlur = () => {
  // 键盘收起后，将top变化的重置回初始值
  stichyTop.value = 0
  window.visualViewport?.removeEventListener('resize', handleVisualViewportChange)
}

// 本地发送消息先上屏
const handleSendMsgLoding = newMessage => {
  // 每次发送消息都要去查一下当前会话的状态
  checkChatStatus()
  // 发送消息+1
  messageSendCount.value += 1
  sendLoading.value = true
  const { MsgID, content } = newMessage
  messages.value.push({
    MsgID,
    MsgType: MessageType.CONTENT_MSG,
    CreateTime: dayjs().valueOf(),
    Content: content,
    Role: 1,
    accessId: MsgID,
    loading: true,
  })
  // 在本地存储一份自己发送的消息的id, 用于区分消息
  messageConunt.value++
  // 将消息状态设置为pending => 等待ai回复的状态
  messageStatus.value = 'pending'
  setTimeout(() => {
    // 消息滚动到底部
    scrollIntoBottom(MsgID)
  }, 200)
}

// 消息发送成功的处理
const handleSendMsg = newMessage => {
  sendLoading.value = false
  const { MsgID, content, accessId } = newMessage
  const findIndex = messages.value.findIndex(v => v.accessId === accessId)
  messages.value.splice(findIndex, 1, {
    MsgID,
    MsgType: MessageType.CONTENT_MSG,
    CreateTime: dayjs().valueOf(),
    Content: content,
    Role: 1,
    accessId: accessId,
    loading: false,
  })
  // 将消息状态设置为pending => 等待ai回复的状态
  messageStatus.value = 'pending'
  setTimeout(() => {
    // 消息滚动到底部
    scrollIntoBottom(MsgID)
  }, 200)
}

// 创建绘画消息
const creatChat = () => {
  if (!aiUserId.value) return
  creatAiChat(aiUserId.value)
    .then(res => {
      if (res.status !== 1000) {
        showToast(res.message)
        return
      }
      const { aiUserInfo, token } = res.content
      const { images } = aiUserInfo
      // ai的信息
      aiUser.value = aiUserInfo
      // 设置aiToken
      localStorage.setItem('ai_chat_token', token)
      // 设置默认好感度
      defaultIntimacy.value = aiUserInfo.default_intimacy
      getMsgHistory()
      bgImage.value = handleImagShow(images[0])
    })
    .catch(err => {
      showToast(err.message)
    })
}

// 拉去历史消息
const getMsgHistory = () => {
  if (!aiUser.value) return
  if (sendLoading.value) return
  getAiChatListMsgHistory({ ...pageParams.value }, aiUserId.value)
    .then(res => {
      // 在消息发送状态的时候，禁止处理消息，避免一些不必要的页面闪烁
      if (sendLoading.value) return
      const { data, next_page } = res
      if (!data) return
      pageParams.value = {
        ...pageParams.value,
        ...next_page,
      }
      messages.value = data
      // 计算一下总分
      scheduleTotal.value = data.reduce((next, prev) => {
        return (prev.IntimacyDelta || 0) + next
      }, +defaultIntimacy.value || 0)
      messageSendCount.value = data.filter(item => item.Role === 1).length
      if (!buttonStatus.value && messageStatus.value === 'inProgress') {
        clearInterval(timer.value)
      }
      // 需要区分的是ai有没有被回复
      if (messageConunt.value > 0 && data.slice(-1)[0].Role === 2) {
        if (messageStatus.value !== 'finally') {
          messageStatus.value = 'inProgress'
        }
        setTimeout(() => {
          // 消息滚动到底部
          scrollIntoBottom(data.slice(-1)[0].MsgID)
        }, 200)
        messageConunt.value--
      }
    })
    .catch(console.error)
}

// 查询当前是否可发送消息
const checkChatStatus = () => {
  getChatStatus(aiUserId.value).then(res => {
    if (!res) return
    const { free_chat_time, chat_time } = res
    freeChatTime.value = free_chat_time
    if (chat_time >= free_chat_time) {
      buttonStatus.value = false
      messageStatus.value = 'finally'
      clearInterval(timer.value)
    }
  })
}

// 推荐回复
const handleRecommendReplyChange = (val: string[]) => {
  recommendReply.value = val
}

// 轮询接口
const hanldeTimer = () => {
  if (timer.value) clearInterval(timer.value)
  // 轮询拉历史消息
  timer.value = setInterval(() => {
    getMsgHistory()
  }, TIME_GET_MSG_HISTORY)
}

watch(messageSendCount, () => {
  if (messageSendCount.value >= freeChatTime.value) {
    buttonStatus.value = false
  }
})

onBeforeMount(() => {
  creatChat()
})

onMounted(() => {
  hanldeTimer()
  // 规避ios 刷新的时候窗口高度不一致的问题
  setTimeout(() => {
    innerHeight.value = window.innerHeight
  }, 300)
  nextTick(() => {
    setTimeout(() => {
      visualViewportHeight.value = window?.visualViewport?.height || 0
    }, 600)
  })
})

onUnmounted(() => {
  clearInterval(timer.value)
})
</script>

<style scoped lang="scss">
.chat {
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: #fff;
  .content {
    flex: 1;
    position: relative;
    z-index: 1;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
  }
  .placeholder {
    width: 100%;
  }
  .stichyTop {
    position: sticky;
    left: 0;
    z-index: 10;
  }
  .botInfo {
    padding: 0 16px;
    margin-top: 16px;
  }
  .bg {
    position: fixed;
    z-index: 0;
    top: 0;
    left: 0;
    height: 100%;
    width: 100vw;
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
  }
}
</style>
